#include "DelegateBuilder.h"
#include "ScriptCompiler/ScriptFileContext.h"
#include "ScriptCompiler/ASTBuilder/TypeBuilder.h"
#include "ScriptCompiler/ASTBuilder/FunctionParameterBuilder.h"
#include "ScriptCompiler/AST/DelegateNode.h"


CDelegateBuilder::CDelegateBuilder(std::shared_ptr<CScriptFileContext> InContext)
{
    Context = InContext;
    Result = std::make_shared<CDelegateNode>(Context);
}

bool CDelegateBuilder::ReadCurentToken()
{
    //check and skip 'delegate' keyword
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type == EScriptTokenType::Delegate)
        {
            Result->Delegate = Token;
            Context->CurrentTokenIndex++;
        }
        else
        {
            Context->RaiseError(10028,Token,U"Expected 'delegate' keyword");
            return false;
        }

    }

    //build return type
    {
        auto TypeBuilder = std::make_shared<CTypeBuilder>(Context);
        if (!TypeBuilder->ReadCurentToken())
        {
            return false;
        }
        Result->ReturnType = TypeBuilder->Result;
    }
    
    //build name
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type == EScriptTokenType::Identifier)
        {
            Result->Name = Token;
            Context->CurrentTokenIndex++;
        }
        else
        {
            Context->RaiseError(10029,Token,U"Expected delegate name");
            return false;
        }
    }


    //build parameters
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type == EScriptTokenType::LeftParentheses)
        {
            Context->CurrentTokenIndex++; //skip '('
        }
        else
        {
            Context->RaiseError(10030,Token,U"Expected '('");
            return false;
        }

        //read parameters
        {
            auto Token = Context->GetCurrentToken();
            if (Token->Type == EScriptTokenType::RightParentheses)
            {
                Context->CurrentTokenIndex++; //skip ')'
            }
            else
            {
                while(true)
                {
                    auto ParameterBuilder = std::make_shared<CFunctionParameterBuilder>(Context);
                    if (!ParameterBuilder->ReadCurentToken())
                    {
                        return false;
                    }
                    Result->Parameters.Add(ParameterBuilder->Result);

                    auto Token = Context->GetCurrentToken();
                    if (Token->Type == EScriptTokenType::RightParentheses)
                    {
                        Context->CurrentTokenIndex++; //skip ')'
                        break;
                    }
                    else if (Token->Type == EScriptTokenType::Comma)
                    {
                        Context->CurrentTokenIndex++; //skip ','
                    }
                    else
                    {
                        Context->RaiseError(10031,Token,U"Expected ',' or ')'");
                        return false;
                    }
                }
            }
        }
    }

    //check and skip ';'
    {
        auto Token = Context->GetCurrentToken();
        if (Token->Type == EScriptTokenType::Semicolon)
        {
            Context->CurrentTokenIndex++;
        }
        else
        {
            Context->RaiseError(10032,Token,U"Expected ';'");
            return false;
        }
    }

    return true;

}
